package com.boat.starter.jetcache.util;

import java.time.Duration;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.TimeUnit;

import com.alicp.jetcache.AutoReleaseLock;
import com.alicp.jetcache.Cache;
import com.boat.starter.jetcache.service.JetcacheContext;
import com.boat.starter.jetcache.service.RedisLockService;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;

/**
 * redis门面类
 * @author 周江
 *
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
@SuppressWarnings(value = { "unchecked", "rawtypes" })
public class RedisUtils {
	private static final JedisPool POOL = JetcacheContext.getSpringContext().getBean(JedisPool.class);
    
//	private static Jedis getJedis() {
//		Pool<Jedis> pool = JetcacheContext.getSpringContext().getBean(Pool.class);
//		return pool.getResource();
//	}
	
	/**
     * 缓存基本的对象，Integer、String、实体类等
     *
     * @param key   缓存的键值
     * @param value 缓存的值
     */
    public static <T> void setCacheObject(final String key, final T value) {
    	try (Jedis jedis = POOL.getResource()) {
            byte[] objectBytes = SerializationUtils.serializeOfValue(value);
            jedis.set(key.getBytes(), objectBytes);
        }
    }
    /**
     * 缓存基本的对象，Integer、String、实体类等
     *
     * @param key      缓存的键值
     * @param value    缓存的值
     * @param duration 时间
     */
    public static <T> void setCacheObject(final String key, final T value, final Duration duration) {
    	try (Jedis jedis = POOL.getResource()) {
            byte[] objectBytes = SerializationUtils.serializeOfValue(value);
            jedis.setex(key.getBytes(), (int)duration.toSeconds(), objectBytes);
        }
    }
    /**
     * 如果不存在则设置 并返回 true 如果存在则返回 false
     *
     * @param key   缓存的键值
     * @param value 缓存的值
     * @return set成功或失败
     */
	public static <T> boolean setObjectIfAbsent(final String key, final T value, final Duration duration) {
		try (Jedis jedis = POOL.getResource()) {
			byte[] objectBytes = SerializationUtils.serializeOfValue(value);
			long result = jedis.setnx(key.getBytes(), objectBytes);
			if (1 == result) {
				jedis.expire(key.getBytes(), (int) duration.toSeconds());
				return true;
			}
			return false;
		}
	}
    
    /**
     * 获得缓存的基本对象。
     *
     * @param key 缓存键值
     * @return 缓存键值对应的数据
     */
    public static <T> T getCacheObject(final String key) {
    	try (Jedis jedis = POOL.getResource()) {
            byte[] objectBytes = jedis.get(key.getBytes());
            if (objectBytes != null) {
                return SerializationUtils.deserializeOfValue(objectBytes);
            }
        }
        return null;
    }
    /**
     * 设置有效时间
     *
     * @param key     Redis键
     * @param timeout 超时时间
     * @return true=设置成功；false=设置失败
     */
    public static boolean expire(final String key, final long timeoutSeconds) {
        return expire(key, Duration.ofSeconds(timeoutSeconds));
    }
    /**
     * 设置有效时间
     *
     * @param key      Redis键
     * @param duration 超时时间
     * @return true=设置成功；false=设置失败
     */
    public static boolean expire(final String key, final Duration duration) {
    	try (Jedis jedis = POOL.getResource()) {
    		long result = jedis.expire(key, (int) duration.toSeconds());
			return 1 == result;
        }
    }
    /**
     * 删除单个对象
     *
     * @param key 缓存的键值
     */
	public static boolean deleteObject(final String key) {
		try (Jedis jedis = POOL.getResource()) {
			long result = jedis.del(key);
			return result > 0;
		}
	}
	
    /**
     * 检查缓存对象是否存在
     *
     * @param key 缓存的键值
     */
    public static boolean isExistsObject(final String key) {
    	try (Jedis jedis = POOL.getResource()) {
			return jedis.exists(key);
		}
    }
    
    /**
     * 获取缓存的当前存活时间,单位：秒
     * @param key
     * @return
     */
    public static long getTimeToLive(final String key) {
    	try (Jedis jedis = POOL.getResource()) {
			return jedis.ttl(key);
		}
    }
    
    /**
     * 根据字符串模式，获得缓存key列表
     *
     * @param pattern 字符串前缀
     * @return 缓存key列表
     */
    public static Collection<String> keys(final String pattern) {
        try (Jedis jedis = POOL.getResource()) {
            // 使用 KEYS 命令获取匹配指定模式的键列表
            Set<String> keys = jedis.keys(pattern);
            return keys;
        }
    }
	/**
	 * 获得redis分布式锁，不管有没有获得锁，都会立刻返回。
	 * 
	 * 注意：
	 * 获得锁后，使用完毕需要调用close()。调用了close()方法，会立即删除缓存key值。
	 * 如不调用close，key值只能等待到期后自动删除
	 * 
	 * 正确使用示例：
	 * try (AutoReleaseLock lock = Jetcache.tryLock(key, 60, TimeUnit.SECONDS);) {
	 * 	  if(lock == null){
	 *        return ;//未获得锁
	 *    }
	 *    
	 *    doSomething();
	 * }
	 * 
	 * @param key
	 * @param expire
	 * @param timeUnit
	 * @return 成功获得锁：返回值不为空；没有获得锁：返回值为null
	 * 
	 */
	public static AutoReleaseLock tryLock(Object key, long expire, TimeUnit timeUnit) {
		Cache cache = JetcacheContext.getSpringContext().getBean(RedisLockService.class).getLockCache();
		return cache.tryLock(key, expire, timeUnit);
	}

	public static boolean tryLockAndRun(Object key, long expire, TimeUnit timeUnit, Runnable action) {
		Cache cache = JetcacheContext.getSpringContext().getBean(RedisLockService.class).getLockCache();
		return cache.tryLockAndRun(key, expire, timeUnit, action);
	}
}
